// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-02-01 // using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using System.Text; using System.Xml.Linq; using System.Xml.Serialization; using JetBrains.Annotations; using LargoCommon.Abstract; using LargoCommon.Interfaces; using LargoCommon.Localization; namespace LargoCommon.Music { /// /// Musical Element. /// public class MusicalElement : IAbstractElement { #region Fields //// //// Last Used Bit. //// //// private int lastUsedBit; /// Complete list of all tones in musical part. private MusicalStrikeCollection musicalTones; #endregion #region Constructors /// /// Initializes a new instance of the class. Unused. /// public MusicalElement() { this.Status = new LineStatus(); this.IsLive = true; this.IsComposed = true; } /// /// Initializes a new instance of the class. /// /// The given status. /// The given previous element. public MusicalElement(LineStatus givenStatus, MusicalElement givenPreviousElement) { this.Status = (LineStatus)givenStatus.Clone(); //// !!!! this.PreviousElement = givenPreviousElement; this.IsLive = true; this.IsComposed = true; } /// /// Initializes a new instance of the class. /// /// The element. /// The header. public MusicalElement(XElement xelement, MusicalHeader header) : this() { Contract.Requires(xelement != null); if (xelement == null) { return; } this.Status = new LineStatus(xelement.Element("Status"), header); } #endregion #region Properties - Xml /// Gets Xml representation. /// Property description. public virtual XElement GetXElement { get { XElement xelement = new XElement("Element"); if (this.Bar == null || this.Line == null) { return xelement; } xelement.Add(new XAttribute("Bar", this.Bar.BarNumber)); xelement.Add(new XAttribute("LineIndex", this.Line.LineIndex)); var xstatus = this.Status.GetXElement; xelement.Add(xstatus); if (this.Tones != null && this.Tones.Count > 0) { var xtones = this.Tones.GetXElement; xelement.Add(xtones); } return xelement; } } #endregion #region Properties /// /// Gets or sets the bar. /// /// /// The bar. /// public IAbstractBar Bar { get; set; } /// /// Gets or sets the track. /// /// /// The track. /// public IAbstractLine Line { get; set; } /// Gets the musical line. /// The musical line. public MusicalLine MusicalLine => (MusicalLine)this.Line; /// /// Gets the point. /// /// /// The point. /// public MusicalPoint Point { get { if (this.Line == null || this.Bar == null) { return new MusicalPoint(0, 0); } return new MusicalPoint(this.Line.LineIndex, this.Bar.BarNumber); } } /// /// Gets or sets Current Musical Track Status. /// public LineStatus Status { get; set; } /// /// Gets or sets a value indicating whether this instance is mute. /// /// /// True if this instance is mute; otherwise, false. /// public bool IsLive { get; set; } //// private set /// /// Gets or sets a value indicating whether this instance is composed. /// /// /// True if this instance is composed; otherwise, false. /// public bool IsComposed { get; set; } //// private set /// /// Gets or sets a value indicating whether this instance is finished = composed. /// /// /// true if this instance is finished; otherwise, false. /// public bool IsFinished { get; set; } //// private set /// /// Gets or sets the previous bar track. /// /// /// The previous bar track. /// public MusicalElement PreviousElement { get; set; } /// /// Gets or sets the previous bar track. /// /// /// The previous bar track. /// public MusicalElement NextElement { get; set; } /// /// Gets or sets the musical tones. /// /// /// The musical tones. /// [XmlIgnore] public MusicalStrikeCollection Tones { get { Contract.Ensures(Contract.Result() != null); return this.musicalTones ?? (this.musicalTones = new MusicalStrikeCollection()); } set => this.musicalTones = value; } /// Gets last but one melodic tone. /// Property description. /// [XmlIgnore] // ReSharper disable once UnusedAutoPropertyAccessor.Local public MusicalTone PreviousBarFirstTone { get; private set; } /// /// Gets or sets the tone packets - detail info about all tones in the element - for tracing; /// /// /// Returns value. /// public TonePacket TonePacket { get; set; } #endregion /// /// Gets or sets the text. /// /// /// The text. /// public string DisplayText { get; set; } /// /// Gets or sets the tool tip. /// /// /// The tool tip. /// public string ToolTip { get; set; } /// /// Gets or sets a value indicating whether this instance has content. /// /// /// true if this instance has content; otherwise, false. /// public bool HasContent { get; set; } /// /// Gets or sets the type of the content. /// /// /// The type of the content. /// public EditorContent ContentType { get; set; } #region Identifiers /// /// Gets the main identifiers. /// /// /// The main identifiers. /// public IList Identifiers { get { var items = new List(); var item = new KeyValuePair("Line type", this.Line.FirstStatus.LineType.ToString()); items.Add(item); item = new KeyValuePair("Line number", this.Line.LineNumber.ToString()); items.Add(item); item = new KeyValuePair("Bar number", this.Bar.BarNumber.ToString()); items.Add(item); var status = this.Status; if (status == null) { return items; } item = new KeyValuePair( LocalizedMusic.String("LocalPurpose"), LocalizedMusic.String(status.LocalPurpose.ToString())); items.Add(item); item = new KeyValuePair("Instrument", status.Instrument.ToString()); items.Add(item); if (status.RhythmicStructure != null) { item = new KeyValuePair( LocalizedMusic.String("Rhythmic structure"), status.RhythmicStructure.ElementString()); items.Add(item); if (status.RhythmicStructure.Level == 1 && status.RhythmicStructure.ToneLevel == 0) { return items; } } item = new KeyValuePair(LocalizedMusic.String("Loudness"), LocalizedMusic.String("Loud" + ((int)status.Loudness).ToString())); items.Add(item); if (status.IsMelodic) { item = new KeyValuePair(LocalizedMusic.String("Octave"), LocalizedMusic.String("Octave" + ((int)status.Octave).ToString())); items.Add(item); item = new KeyValuePair(LocalizedMusic.String("Melodic shape"), LocalizedMusic.String("MelodicShape" + ((int)status.MelodicShape).ToString())); items.Add(item); item = new KeyValuePair(LocalizedMusic.String("Melodic function"), LocalizedMusic.String("MelodicFunction" + ((int)status.MelodicFunction).ToString())); items.Add(item); if (status.MelodicStructure != null) { item = new KeyValuePair( LocalizedMusic.String("Melodic structure"), status.MelodicStructure.ElementString()); items.Add(item); } item = new KeyValuePair(LocalizedMusic.String("Band"), LocalizedMusic.String("Band" + ((int)status.BandType).ToString())); items.Add(item); item = new KeyValuePair(LocalizedMusic.String("Tone level"), status.ToneLevel.ToString(CultureInfo.InvariantCulture)); items.Add(item); item = new KeyValuePair(LocalizedMusic.String("Beat level"), status.BeatLevel.ToString(CultureInfo.InvariantCulture)); items.Add(item); item = new KeyValuePair(LocalizedMusic.String("Priority"), status.Priority.ToString()); items.Add(item); } /* Unused - not ready - identifiers item = new KeyValuePair(LocalizedMusic.String("Melodic direction"), this.MelodicDirection.ToString(CultureInfo.InvariantCulture)); items.Add(item); item = new KeyValuePair(LocalizedMusic.String("Melodic genus"), this.MelodicGenus.ToString()); items.Add(item); item = new KeyValuePair(LocalizedMusic.String("Rhythmic tension"), this.RhythmicTension.ToString(CultureInfo.InvariantCulture)); items.Add(item); */ return items; } } #endregion /// /// Determines whether [is compatible with] [the specified given musical unit]. /// /// The given element. /// /// true if [is compatible with] [the specified given musical unit]; otherwise, false. /// public bool IsCompatibleWith(MusicalElement givenElement) { return this.HasContent && givenElement.DisplayText == this.DisplayText; } #region Public methods /// Makes a deep copy of the MusicalElement object. /// Returns object. public object Clone() { var element = new MusicalElement { Bar = this.Bar, Line = this.Line, Status = (LineStatus)this.Status.Clone(), Tones = this.Tones.Clone(true) }; //// 2016/08 return element; } /// /// Sets the tones. /// /// The given tones. public void SetTones(MusicalStrikeCollection givenTones) { this.Tones = givenTones; } /// /// Prepares the tone packets. /// public void PrepareTonePacket() { this.TonePacket = new TonePacket(this.Tones); } /// /// Prepares the content. /// /// Type of the given content. public void PrepareContent(EditorContent givenContentType) { this.DisplayText = string.Empty; this.ToolTip = null; this.HasContent = false; var status = this.Status; if (!status.HasContent) { return; } this.ContentType = givenContentType; switch (givenContentType) { case EditorContent.Cell: { var sb = new StringBuilder(); if (status?.ToneLevel > 0 || status?.MelodicFunction != MelodicFunction.None) { //// || status?.MelodicShape != MelodicShape.None sb.AppendLine(status?.ToneLevel.ToString() + " " + status?.MelodicShape.ToString()); sb.Append(status?.MelodicFunction.ToString()); } this.DisplayText = sb.ToString(); //// this.Point.ToString(); this.ToolTip = status.GetTooltip; break; } case EditorContent.RhythmicStructure: { this.DisplayText = status.RhythmicStructure != null ? status.RhythmicStructure.ElementSchema : string.Empty; this.ToolTip = status.GetTooltip; break; } case EditorContent.MelodicStructure: { this.DisplayText = status.MelodicStructure != null ? status.MelodicStructure.ElementSchema : string.Empty; this.ToolTip = status.GetTooltip; break; } case EditorContent.MelodicFunction: { this.DisplayText = status.MelodicFunction.ToString(); this.ToolTip = status.GetTooltip; break; } case EditorContent.Loudness: { this.DisplayText = status.Loudness.ToString(); this.ToolTip = status.GetTooltip; break; } case EditorContent.RhythmicMotive: { this.DisplayText = status.RhythmicMotive != null ? status.RhythmicMotive.Name : string.Empty; this.ToolTip = status.GetTooltip; break; } case EditorContent.MelodicMotive: { this.DisplayText = status.MelodicMotive != null ? status.MelodicMotive.Name : string.Empty; this.ToolTip = status.GetTooltip; break; } case EditorContent.Band: { this.DisplayText = status.BandType.ToString(); this.ToolTip = status.GetTooltip; break; } case EditorContent.Octave: { this.DisplayText = status.Octave.ToString(); this.ToolTip = status.GetTooltip; break; } case EditorContent.Instrument: { this.DisplayText = status.Instrument.ToString(); this.ToolTip = status.GetTooltip; break; } case EditorContent.BeatLevel: { this.DisplayText = status.BeatLevel.ToString(); this.ToolTip = status.GetTooltip; break; } case EditorContent.ToneLevel: { this.DisplayText = status.ToneLevel.ToString(); this.ToolTip = status.GetTooltip; break; } case EditorContent.MelodicShape: { this.DisplayText = status.MelodicShape.ToString(); this.ToolTip = status.GetTooltip; break; } } this.HasContent = true; } /// /// Sets the melodic pattern. /// /// The given pattern. /// The given line. /// if set to true [keep original arrange]. [UsedImplicitly] public void EditorSetMelodicPattern(MelodicPattern givenPattern, byte givenLine, bool keepOriginalArrange) { if (givenLine >= givenPattern.Voices.Count) { return; } var voice = givenPattern.Voices[givenLine]; this.Tones = voice.Tones; this.Status.System = this.Bar.Header.System; this.Status.SetMelodicPatternVoice(voice, keepOriginalArrange); } /// /// Sets the melodic pattern. /// /// The given pattern. /// The given line. /// if set to true [keep original arrange]. [UsedImplicitly] public void EditorSetRhythmicPattern(RhythmicPattern givenPattern, byte givenLine, bool keepOriginalArrange) { if (givenLine >= givenPattern.Voices.Count) { return; } var voice = givenPattern.Voices[givenLine]; this.Tones = voice.Tones; this.Status.System = this.Bar.Header.System; this.Status.SetRhythmicPatternVoice(voice, keepOriginalArrange); } /// /// Makes the status from tones. /// public void SetElementStatusFromTones() { var trackStatus = this.MusicalLine.FirstStatus; if (this.Status == null || trackStatus == null) { return; } //// Real track properties this.Status.BarNumber = this.Bar.BarNumber; //// 2018/12 this.Status.MelodicVariety = trackStatus.MelodicVariety; //// this.Status.Channel = trackStatus.Channel; this.Status.Staff = trackStatus.Staff; this.Status.Voice = trackStatus.Voice; //// this.Status.HarmonicModalization = trackStatus.HarmonicModalization; //// Problem of repeated reading of MIF file .... *** if (this.Status.LineType == MusicalLineType.None && trackStatus.LineType != MusicalLineType.None) { this.Status.LineType = trackStatus.LineType; } if (this.Status.LocalPurpose == LinePurpose.None && trackStatus.LocalPurpose != LinePurpose.None) { this.Status.LocalPurpose = trackStatus.LocalPurpose; //// 2018/12 } //// *** var barAllTones = this.Tones; //// var isMelodic = this.Status.IsMelodic; //// var barTones = isMelodic ? this.SingleMelodicTones() : null; var melodicTonesInBar = this.SingleMelodicTones(); if (barAllTones == null || barAllTones.Count == 0) { return; } //// *** Loudness *** var loudness = melodicTonesInBar.MeanLoudness; this.Status.Loudness = loudness; //// *** Rhythmic tension *** var rstruct = barAllTones.DetermineRhythmicStructure(this.Bar.Header.System.RhythmicOrder); this.Status.RhythmicStructure = rstruct; this.Status.ToneLevel = rstruct.ToneLevel; this.Status.BeatLevel = rstruct.Level; this.Status.RhythmicTension = (byte)rstruct.FormalBehavior.Variance; //// Melodic structure in bar - from tones var isMelodic = this.Status.IsMelodic; if (isMelodic) { if (melodicTonesInBar != null && melodicTonesInBar.Any()) { //// lastMelodicTone var mstruct = melodicTonesInBar.DetermineMelodicStructure(null, this.Bar.HarmonicBar); if (mstruct == null) { var system = new MelodicSystem(1, 1); mstruct = new MelodicStructure(system, 1); } this.Status.MelodicStructure = mstruct; } } //// *** StaffChange *** var firstTone = barAllTones.FirstOrDefault(); if (firstTone != null) { this.Status.Staff = firstTone.Staff; this.Status.Voice = firstTone.Voice; } //// 2016/06 //// *** Instrument *** if (this.Status.Instrument.IsEmpty) { if (this.Status.LineType == MusicalLineType.Melodic) { this.Status.Instrument = new MusicalInstrument(barAllTones.FirstMelodicInstrument); } if (this.Status.LineType == MusicalLineType.Rhythmic) { this.Status.Instrument = new MusicalInstrument(barAllTones.FirstRhythmicInstrument); } } //// *** Octaves *** this.Status.Octave = melodicTonesInBar.MeanOctave; this.Status.BandType = MusicalProperties.BandTypeFromOctave(this.Status.Octave); //// 2016/10 if (this.Tones.Count > 0) { this.Status.MelodicPlan = new MelodicPlan(this.Tones); } this.Status.MelodicFunction = melodicTonesInBar.DetermineMelodicType(this.Bar.HarmonicBar); this.Status.MelodicShape = MelodicShape.Scales; } /// /// List of tones in one bar of musical part. /// /// /// Returns value. /// public MusicalToneCollection SingleMelodicTones() { var tones = from mT in this.Tones where mT.ToneType == MusicalToneType.Melodic && !mT.IsPause orderby mT.BitFrom select mT; var mtc = new MusicalToneCollection(); //// Only one tone of each cluster var lastBitFrom = -1; // ReSharper disable once LoopCanBePartlyConvertedToQuery foreach (var tone in tones) { MusicalTone mtone = tone as MusicalTone; if (mtone == null) { continue; } if (mtone.BitFrom == lastBitFrom) { continue; } mtc.Add(mtone); lastBitFrom = mtone.BitFrom; } return mtc; } /// /// List of tones in one bar of musical part. /// /// The bar numbers back. /// The bar numbers forward. /// /// Returns value. /// public MusicalToneCollection MelodicTonesAround(int barNumbersBack, int barNumbersForward) { var atones = new List(); MusicalElement element = this; for (int stepDown = 0; stepDown <= barNumbersBack && element != null; stepDown++) { var mts = this.Tones.Where(x => x != null && x.ToneType == MusicalToneType.Melodic && x.Loudness > 0); atones.AddRange(mts); element = element.PreviousElement; } element = this; for (int stepUp = 0; stepUp <= barNumbersForward && element != null; stepUp++) { var mts = this.Tones.Where(x => x != null && x.ToneType == MusicalToneType.Melodic && x.Loudness > 0); atones.AddRange(mts); element = element.NextElement; } var distinctTones = new MusicalToneCollection(); foreach (var tone in atones) { var mt = tone as MusicalTone; if (mt?.Pitch == null) { continue; } var mt1 = mt; var ex = from mtone in distinctTones where mtone.Pitch.Element == mt1.Pitch.Element select mtone; if (!ex.Any()) { distinctTones.Add(mt); } if (distinctTones.Count >= 7) { break; } } return distinctTones; } /// /// Musicals the tone at. /// /// The tick. /// The rhythmic structure. /// Returns value. public MusicalStrike MusicalToneAt(byte tick, FiguralStructure rhythmicStructure) { //// RhythmicStructure if (rhythmicStructure == null) { return null; } var level = rhythmicStructure.LevelOfBit(tick); return (level < this.Tones.Count ? this.Tones[level] : null) as MusicalStrike; } #endregion /// /// Composes from plan. /// public void ComposeFromPlan() { this.Status.RhythmicStructure = this.GetRhythmicStructure(); } /* Compose Rhythm From Plan st.RhythmicStructure = new RhythmicStructure(header.System.RhythmicSystem, 0); byte tick = (byte)(systemLength % 12); if (element.IsEmpty) { st.RhythmicStructure.SetElement(tick, 2); } else { st.RhythmicStructure.SetElement(tick, 1); } st.RhythmicStructure.CompleteFromElements(); st.RhythmicStructure.DetermineToneLevel(); */ /// Gets rhythmic structure. /// The rhythmic structure. public RhythmicStructure GetRhythmicStructure() { RhythmicSystem rhythmicSystem = this.Bar.Header.System.RhythmicSystem; string structuralCode = string.Empty; switch (this.Status.RhythmicFace?.Name) { case "Regular whole-note": { structuralCode = "1,23*0"; break; } case "Regular half-notes": { structuralCode = "1,11*0,1,11*0"; break; } case "Regular triads": { structuralCode = "1,7*0,1,7*0,1,7*0"; break; } case "Regular quarters": { structuralCode = "1,5*0,1,5*0,1,5*0,1,5*0"; break; } case "Regular sixths": { structuralCode = "1,3*0,1,3*0,1,3*0,1,3*0,1,3*0,1,3*0"; break; } case "Regular eighths": { structuralCode = "1,2*0,1,2*0,1,2*0,1,2*0,1,2*0,1,2*0,1,2*0,1,2*0"; break; } case "Regular twelfths": { structuralCode = "1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0"; break; } case "Empty": { structuralCode = string.Empty; break; } } var rs = new RhythmicStructure(rhythmicSystem, structuralCode); return rs; } /// /// Composes the tone. /// /// The melodic tone. public void ComposeTone(MusicalTone musicalTone) { Contract.Requires(musicalTone != null); Contract.Requires(this.Status != null); //// Contract.Requires(this.Line.CurrentTone != null); musicalTone.SetPitch(new MusicalPitch(this.Bar.Header.System.HarmonicSystem)); //// this.HarmonicModality = null; bool singleHarmony = true; //// 2018/10 var hstruct = this.Bar.HarmonicBar?.PrevailingHarmonicStructure(musicalTone.BitRange, out singleHarmony); //// (musicalBar.Number) if (hstruct != null && hstruct.Level == 0) { hstruct = null; } var modalization = MusicalSettings.Singleton.HarmonicModalization; if (modalization == HarmonicModalizationType.Consecutive) { //// != HarmonicModalizationType.Forced this.Status.HarmonicModality = this.DetermineHarmonicModality(hstruct); //// , this.Status.HarmonicModalization } if (modalization == HarmonicModalizationType.Forced) { //// != HarmonicModalizationType.Forced this.Status.HarmonicModality = MusicalSettings.Singleton.ForcedModality; } //// harStruct.SetHarModality(hm); if (this.Status.HarmonicModality == null) { return; } this.MusicalLine.CurrentTone = musicalTone; var melodicVariety = this.MusicalLine.FirstStatus.MelodicVariety; //// Status.MelodicVariety; if (melodicVariety == null) { return; } if (!melodicVariety.GeneratePossibilities( this.MusicalLine.CurrentTone, this.Status.HarmonicModality, hstruct, this.Status.IsHarmonic && singleHarmony)) { return; } var newMelTone = melodicVariety.OptimalNextMelTone(this.MusicalLine.CurrentTone); if (!this.Status.IsMelodic) { return; } musicalTone.SetMelTone(newMelTone); this.CompleteMelodicTone(musicalTone); } #region Public methods - Loudness /// /// Determine loudness of the tone. /// /// Rhythmical structure. /// Range of tone. /// /// Returns value. /// public MusicalLoudness DetermineLoudness(FiguralStructure rhythmicStruct, BitRange toneRange) { Contract.Requires(rhythmicStruct != null); Contract.Requires(toneRange != null); if (rhythmicStruct == null) { return 0; } //// if (toneRange == null) { return 0; } if (rhythmicStruct.IsPauseStart(toneRange.BitFrom)) { return 0; } var status = this.Status; byte loudness; if (MusicalSettings.Singleton.CorrectLoudness) { loudness = this.CorrectLoudness(toneRange, (byte)(status != null ? (byte)status.Loudness : 0)); } else { loudness = (byte)(status != null ? (byte)status.Loudness : 0); } if (status != null && (status.IsMelodicalNature && status.MelodicFunction == MelodicFunction.MelodicMotion && MusicalSettings.Singleton.HighlightMelodicVoices)) { loudness = (byte)Math.Min(loudness + 4, (byte)MusicalLoudness.MaxLoudness); } return (MusicalLoudness)loudness; } #endregion #region Public methods - Quantities /// Prepares current melodic interval. /// Returns value. public bool PrepareMelInterval() { var line = (MusicalLine)this.Line; if ((line.LastTone != null) && (line.CurrentTone != null) && (!line.LastTone.IsEmpty && !line.CurrentTone.IsEmpty)) { ////201508 this.ComposedTrack.TrackEngine this.Status.CurrentMelInterval = new MelodicInterval(this.Bar.Header.System.HarmonicSystem, line.LastTone.Pitch, line.CurrentTone.Pitch); return true; //// this._MelInterval.SetHarmonicProperties(); } this.Status.CurrentMelInterval = null; return false; } #endregion #region Public methods - Rhythmic /// /// Fills the with rhythm. /// public void FillWithRhythm() { switch (this.Status?.LocalPurpose) { case LinePurpose.Composed: this.FillWithRequestedRhythm(); break; case LinePurpose.Fixed: this.FillWithRhythmOfTones(this.Tones); //// 2016 .MusicalTonesInBar(this.Number)//// 2014/01 break; } } /// /// Creates one bar of rhythm in this musical part. /// /// Rhythmical structure. /// Musical Loudness. public void FillWithRhythm(RhythmicStructure rhythmicStruct, MusicalLoudness givenLoudness) { Contract.Requires(rhythmicStruct != null); Contract.Requires(this.Status != null); this.Status.RhythmicStructure = rhythmicStruct; //// !!!!!!!!! attention! if (this.Status.RhythmicStructure != null) { if (this.Tones.Any()) { //// 2019/02 !?! this.Tones.Clear(); } var binStruct = this.Status.RhythmicStructure.BinaryStructure(true); var binSchema = new BinarySchema(binStruct); if (this.Status.RhythmicStructure.IsFromPreviousBar) { this.SolveToneFromPreviousBar(givenLoudness); } this.AppendTonesAccordingToRhythm(givenLoudness, binSchema); } ////2016 this.Status.ReflectChange(); } /// /// Compose rhythm of lines in given bar. /// public void FillWithRequestedRhythm() { Contract.Requires(this.Status != null); if (this.Status == null) { return; } if (this.Tones.Any()) { //// 2019/02 !?! this.Tones.Clear(); } //// this.Status.RhythmicMotive = this.Status.RhythmicMotive; if (this.Status.RhythmicStructure != null || this.Status.RhythmicMotive != null) { var rhyStruct = this.DetermineRhythmicStructure(false); var loudness = this.Status.Loudness; this.FillWithRhythm(rhyStruct, loudness); } var addEmptyRange = this.Status.RhythmicStructure == null; if (!addEmptyRange) { return; } this.FillWithPause(); } /// /// Fills the with pause. /// public void FillWithPause() { var range = new BitRange(this.Bar.Header.System.RhythmicOrder, 0, this.Bar.Header.System.RhythmicOrder); //// 2019/02 var musicalPause = new MusicalPause(range, this.Bar.BarNumber); //// var musicalStrike = new MusicalStrike(MusicalToneType.Empty, range, 0, this.Bar.BarNumber); if (this.Status != null) { musicalPause.InstrumentNumber = this.Status.Instrument.Number; musicalPause.Staff = this.Status.Staff; musicalPause.Voice = this.Status.Voice; } this.Tones.Add(musicalPause); } /// /// Fills the with rhythm of tones. /// /// The given tones. public void FillWithRhythmOfTones(MusicalStrikeCollection givenTones) { var rorder = this.Bar.Header.System.RhythmicOrder; this.Status.RhythmicStructure = new RhythmicStructure(rorder, givenTones); //// 2016 .MusicalTonesInBar(this.Number)//// 2014/01 } /// /// Rhythmic structure in bar. /// /// If set to true [fill empty]. /// /// Returns value. /// public RhythmicStructure DetermineRhythmicStructure(bool fillEmpty) { Contract.Requires(this.Status.RhythmicMotive != null); if (this.Status.RhythmicStructure != null) { return this.Status.RhythmicStructure; } int barIndex = 0; //// why there is sometimes (after chuffle...) barNumber < this.Status.BarNumber ??? if (this.Bar.BarNumber >= this.Status.RhythmicMotiveStartBar) { //// && this.ComposedTrack.Status.BarNumber.HasValue //// // here have to be bar-number of the rhythmical motive start //// // this.BarNumber is bar number of the last change barIndex = this.Bar.BarNumber - this.Status.RhythmicMotiveStartBar + 1; } if (barIndex < 1) { return null; } //// 2016 - stop changes ? if (barIndex > this.RhythmicMotive.Length) { return null; } var rhythmicOrder = this.Bar.Header.System.RhythmicOrder; var rhyStructCode = this.Status.RhythmicMotive.RhythmicStructuralCodeForBar(barIndex); if (string.IsNullOrEmpty(rhyStructCode)) { rhyStructCode = fillEmpty ? "2" : "1"; } var rsystem = RhythmicSystem.GetRhythmicSystem(RhythmicDegree.Structure, rhythmicOrder); var rstruct = RhythmicStructure.GetNewRhythmicStructure(rsystem, rhyStructCode); //// rhyStructNumber return rstruct; } /// /// Determines the melodic structure. /// /// Returns value. [UsedImplicitly] public MelodicStructure DetermineMelodicStructure() { Contract.Requires(this.Status.MelodicMotive != null); int barIndex = 0; //// why there is sometimes (after chuffle...) barNumber < this.Status.BarNumber ??? if (this.Bar.BarNumber >= this.Status.MelodicMotiveStartBar) { //// && this.ComposedTrack.Status.BarNumber.HasValue //// // here have to be bar-number of the rhythmical motive start //// // this.BarNumber is bar number of the last change barIndex = this.Bar.BarNumber - this.Status.MelodicMotiveStartBar + 1; } if (barIndex < 1) { return null; } //// 2016, see stop changes... if (barIndex > this.MelodicMotive.Length) { return null; } var mms = this.Status.MelodicMotive.MelodicStructureInBar(barIndex); return mms; } /// /// Completes the melodic tone. /// /// The melodic tone. public void CompleteMelodicTone(MusicalStrike musicalTone) { Contract.Requires(musicalTone != null); var line = this.MusicalLine; MusicalStrike.CorrectBadBinding(line.LastTone, musicalTone); //// mt.OrdinalIndex = this.MusicalTones.IndexOf(mt); ////?! if (line.LastTone != null && !line.LastTone.IsEmpty) { line.PenultTone = (MusicalTone)line.LastTone.Clone(); } musicalTone.BarNumber = this.Bar.BarNumber; if (musicalTone.BitRange != null) { var loudness = this.DetermineLoudness(this.Status.RhythmicStructure, musicalTone.BitRange); //// (musicalBar.Number) musicalTone.Loudness = loudness; } var status = this.Status; musicalTone.InstrumentNumber = status.Instrument.Number; //// musicalTone.Channel = (MidiChannel)status.InstrumentStatus.Channel; musicalTone.Staff = status.Staff; musicalTone.Voice = status.Voice; //// mt.Type = MusicalToneType.Melodic; } /// /// Swaps the melodic with. /// /// The element. public void SwapMelodicWith(MusicalElement element) { Contract.Requires(element != null); var musicalOctave = element.Status.Octave; element.Status.Octave = this.Status.Octave; this.Status.Octave = musicalOctave; var melodicType = element.Status.MelodicFunction; element.Status.MelodicFunction = this.Status.MelodicFunction; this.Status.MelodicFunction = melodicType; var melodicStructure = element.Status.MelodicStructure; element.Status.MelodicStructure = this.Status.MelodicStructure; this.Status.MelodicStructure = melodicStructure; } #endregion #region Public methods - Modification /// /// Alter octaves by random. /// public void RandomAlterOctave() { if (this.Status.Octave == MusicalOctave.None) { this.Status.Octave = MusicalOctave.OneLine; return; } var increment = MathSupport.RandomNatural(2) == 0 ? 1 : -1; var octave = (int)this.Status.Octave + increment; if (octave >= (int)MusicalOctave.ThreeLine) { octave = (int)MusicalOctave.ThreeLine; } if (octave <= (int)MusicalOctave.Small) { octave = (int)MusicalOctave.Small; } this.Status.Octave = (MusicalOctave)octave; } /// /// Shifts the line octave. /// /// The number of octaves. public void ShiftOctave(int numberOfOctaves) { if (this.Status.Octave == MusicalOctave.None) { this.Status.Octave = MusicalOctave.OneLine; return; } var n = (int)this.Status.Octave + numberOfOctaves; n = Math.Min(n, (int)MusicalOctave.FiveLine); n = Math.Max(n, (int)MusicalOctave.SubContra); this.Status.Octave = (MusicalOctave)n; } #endregion #region String representation /// String representation of the object. /// Returns value. public override string ToString() { var s = new StringBuilder(); s.AppendFormat( " Bar {0} line {1} mel:{2} rhy:{3} R:{4}", this.Point.BarNumber, this.Point.LineIndex, this.Status.IsMelodicOriginal, this.Status.IsRhythmicOriginal, this.Status.RhythmicStructure != null ? this.Status.RhythmicStructure.ElementSchema : string.Empty); return s.ToString(); } /// /// To the progress string. /// /// Returns value. public string ToProgressString() { var s = new StringBuilder(); s.AppendFormat( " Bar {0} / Line {1}", this.Point.BarNumber, this.Point.LineIndex); return s.ToString(); } #endregion #region Private methods /// /// Solves the tone from previous bar. /// /// The given loudness. private void SolveToneFromPreviousBar(MusicalLoudness givenLoudness) { var toneRange = this.Status.RhythmicStructure.OverrunRange(); if (toneRange == null) { return; } //// MusicalStrike lastTone = ((Collection)this.MusicalTones).ElementAt(this.MusicalTones.Count()-1); var lastTone = this.Tones.LastOrDefault(); if (lastTone == null) { return; } lastTone.IsGoingToNextBar = MusicalSettings.Singleton.LongTones; //// true; var tone = this.PrepareTone(givenLoudness, toneRange); tone.IsFromPreviousBar = MusicalSettings.Singleton.LongTones; //// true; this.Tones?.Add(tone); //// this.Line.AddMusicalTone(musicalStrike); } /// /// Prepares the tone. /// /// The given loudness. /// The tone range. /// /// Returns value. /// private MusicalStrike PrepareTone(MusicalLoudness givenLoudness, BitRange toneRange) { Contract.Requires(toneRange != null); MusicalStrike tone; var loudness = this.Status.RhythmicStructure != null && this.Status.RhythmicStructure.IsPauseStart(toneRange.BitFrom) ? MusicalLoudness.None : givenLoudness; if (this.Status.LineType == MusicalLineType.Melodic) { tone = new MusicalTone(null, toneRange, loudness, this.Bar.BarNumber); } else { if (this.Status.RhythmicStructure != null) { loudness = givenLoudness; //// (byte)MusicalLoudness.MeanLoudness; //// this.DetermineLoudness(musicalBar, this.Status.RhythmicStructure, toneRange); } tone = new MusicalStrike(MusicalToneType.Rhythmic, toneRange, loudness, this.Bar.BarNumber); } if (!this.Status.IsRhythmic) { return tone; } //// 201508 if (this.Status.RhythmicStructure != null && musicalStrike.BitRange != null) { //// loudness = this.TrackEngine.DetermineLoudness(musicalBar, this.Status.RhythmicStructure, musicalStrike.BitRange); } //// (musicalBar.Number) tone.Loudness = loudness; tone.InstrumentNumber = this.Status.Instrument.Number; //// musicalStrike.Channel = (MidiChannel)this.Status.InstrumentStatus.Channel; tone.Staff = this.Status.Staff; tone.Voice = this.Status.Voice; return tone; } /// /// Appends the tones according to rhythm. /// /// The given loudness. /// The bin schema. private void AppendTonesAccordingToRhythm(MusicalLoudness givenLoudness, BinarySchema binSchema) { Contract.Requires(binSchema != null); var level = this.Status.RhythmicStructure.Level; //// not ToneLevel BitRange toneRange = null; for (byte i = 0; i < level; i++) { if (this.Status.RhythmicStructure != null) { if (i >= binSchema.Level) { i = 0; } toneRange = binSchema.RangeAtLevel(i); // toneRange = [ MaskedBitRange]; } if (toneRange == null || toneRange.Length == 0) { continue; } var tone = this.PrepareTone(givenLoudness, toneRange); if (this.Tones != null) { tone.OrdinalIndex = this.Tones.Count; this.Tones.Add(tone); } } } /// /// Assign Harmonic Modality. /// /// Prevailing HarmonicStructure. /// /// Returns value. /// private HarmonicModality DetermineHarmonicModality(HarmonicStructure prevailingHarmonicStructure) { Contract.Requires(this.Bar.HarmonicBar.HarmonicMotive != null); //// Contract.Requires(musicalBar.HarmonicBar.HarmonicMotive.HarmonicCore != null); //// if (musicalBar == null) { return null; } HarmonicModality modality = null; var minModalityLevel = MusicalSettings.Singleton.MinimalModalityLevel; var modalization = MusicalSettings.Singleton.HarmonicModalization; switch (modalization) { //// 0. Chromatic only case HarmonicModalizationType.Chromatic: { //// modality = null; break; } //// 1. Modality from structures in the bar after it disappears } (hstruct.Number & this.HarmonicModality.Number)==0)) (current settings) case HarmonicModalizationType.Consecutive: { if (prevailingHarmonicStructure != null) { modality = prevailingHarmonicStructure.HarmonicModality; if (modality == null || modality.Level < minModalityLevel || ((prevailingHarmonicStructure.Number & modality.Number) == 0)) { modality = ((MusicalBar)this.Bar).HarmonicModalityFromStructures(MusicalSettings.Singleton.MinimalModalityLevel); } } break; } //// 2. Forced from above case HarmonicModalizationType.Forced: modality = MusicalSettings.Singleton.ForcedModality; break; } if (modality != null) { return modality; } //// Chromatic modality is default value, when other assignments failed modality = this.Bar.Header.System.HarmonicSystem.ChromaticModality; return modality; } /// /// Corrects the loudness. According to dynamic rules. /// /// The tone range. /// The loudness. /// /// Returns value. /// private byte CorrectLoudness(BitRange toneRange, byte loudness) { Contract.Requires(toneRange != null); const byte consonanceLimit = 60; if (toneRange.BitFrom == 0) { loudness++; } else { if (toneRange.Length > 1) { loudness++; } if (toneRange.Length > 3) { loudness++; } } if (this.Status.LineType != MusicalLineType.Melodic || this.Bar == null) { return loudness; } var cluster = ((MusicalBar)this.Bar).HarmonicClusterAtTick(toneRange.BitFrom); if (cluster == null) { return loudness; } var v = cluster.RealEnergy.Consonance; //// .FormalConsonance); if (v < consonanceLimit) { loudness++; } return loudness; } #endregion } }